package servidores;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;

public class ThreadClienteCatalogo extends Thread {
   
    private Socket socketClienteCatalogo;
    private ObjectInputStream flujoEntrada;
    private ObjectOutputStream flujoSalida;
    private List <Socket> listaClientesCatalogo;
    
    private static final String JDBC_DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver";        
    private static final String DATABASE_URL = "jdbc:odbc:dbSO";
	private static final String QUERY_INICIAL = "select * from Libros";
	private static final String QUERY_TEMA = "select * from Libros where tema = ?";
	private static final String QUERY_TITULO = "select * from Libros where titulo like ?";
	private static final String QUERY_TEMATITULO = "select * from Libros where tema = ? and titulo like ?";
	private Connection connection;
	private Statement statement;
	private PreparedStatement pstatement;
    
    public ThreadClienteCatalogo(Socket socketClientCatalogo, List<Socket> listaClientsCatalogo) throws IOException {
        this.socketClienteCatalogo = socketClientCatalogo;
	    this.flujoSalida = new ObjectOutputStream(socketClientCatalogo.getOutputStream());    
    	this.flujoEntrada = new ObjectInputStream(socketClientCatalogo.getInputStream()); 
        this.listaClientesCatalogo = listaClientsCatalogo;
		try {
			Class.forName(JDBC_DRIVER);
			this.connection = DriverManager.getConnection(DATABASE_URL,"root","sergio");
			this.statement = connection.createStatement();
		} catch (ClassNotFoundException e) {
			sendToClient("Error al conectarse a la base de datos: Driver",flujoSalida);
		} catch (SQLException e) {
			sendToClient("Error al conectarse a la base de datos: Connect",flujoSalida);
		}

    }
   
    public void run () {
        try {
            while (true) {
                String mensaje = flujoEntrada.readUTF();
                System.out.println("BackEnd-Catalogo: Ejecutando " + mensaje + "[threadId: " + this.getId() + "]");
                if ("listaTemas".equalsIgnoreCase(mensaje)) {
                	try {
                	    sendToClient(getListaTemas(),flujoSalida);
					} catch (SQLException e) {
                	    sendToClient("Error getListaTemas()",flujoSalida);
						e.printStackTrace();
					}
                }
                if ("listaLibros".equalsIgnoreCase(mensaje)) {
                	try {
                	    sendToClient(getListaLibros(),flujoSalida);
					} catch (SQLException e) {
                	    sendToClient("Error getListaLibros()",flujoSalida);
						e.printStackTrace();
					}
                }
                if ("listaXtema".equalsIgnoreCase(mensaje.substring(0,10))) {
                	try {
                	    sendToClient(getListaLibros(mensaje.substring(11)),flujoSalida);
					} catch (SQLException e) {
                	    sendToClient("Error getListaLibros(tema)",flujoSalida);
						e.printStackTrace();
					}
                }
                if ("listaXtitu".equalsIgnoreCase(mensaje.substring(0,10))) {
                	try {
                	    sendToClient(getListaLibrosTitulo(mensaje.substring(11)),flujoSalida);
					} catch (SQLException e) {
                	    sendToClient("Error getListaLibrosTitulo(titulo)",flujoSalida);
						e.printStackTrace();
					}
                }  
                if ("listaXtite".equalsIgnoreCase(mensaje.substring(0,10))) {
                	try {
                	    sendToClient(getListaLibrosTemaTitulo(mensaje.substring(11)),flujoSalida);
					} catch (SQLException e) {
                	    sendToClient("Error getListaLibrosTemaTitulo(tema|titulo)",flujoSalida);
						e.printStackTrace();
					}
                }   
            }
        }
        catch (IOException ex) {
        	System.out.println("BackEnd-Catalogo: Un Cliente se ha desconectado [threadId: " + this.getId() + "]");
        	//ex.printStackTrace();
        }
        finally {
        	listaClientesCatalogo.remove(this.socketClienteCatalogo);
        	try {
				desconectar();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            cerrarFlujos();
        }
    }
    
    private void sendToClient(Object mensaje, ObjectOutputStream flujoSalida) {
        try {
            flujoSalida.writeObject(mensaje);
            flujoSalida.flush();
        }    
        catch (IOException ex) {
        	System.out.println("BackEnd-Catalogo: Error en sendToClient [threadId: " + this.getId() + "]");
            ex.printStackTrace();                 
        } 
    } 

    private void cerrarFlujos() { 
        try {
             flujoEntrada.close();
             flujoSalida.close();
             socketClienteCatalogo.close();
        }
        catch (IOException ex) {
        	System.out.println("BackEnd-Catalogo: Error en cerrarFlujos [threadId: " + this.getId() + "]");
        	ex.printStackTrace();
        }        
    }
    
	public Object getListaLibros() throws SQLException {
		List <String>  listaLibros = new ArrayList<String>();
		
		ResultSet datosRS = statement.executeQuery(QUERY_INICIAL);
		
		while (datosRS.next()) {
			Libro libro = new Libro();
			
			libro.setId_libro(datosRS.getInt("id_libro"));
			libro.setTema(datosRS.getString("tema"));
			libro.setTitulo(datosRS.getString("titulo"));
			libro.setStock(datosRS.getInt("stock"));
			libro.setCosto(datosRS.getInt("costo"));			
			
			listaLibros.add(libro.serialize());
		}
		
		return (Object) listaLibros;
	}
	
	public Object getListaTemas() throws SQLException {
		List <String>  listaTemas = new ArrayList<String>();
		
		ResultSet datosRS = statement.executeQuery("select distinct tema from Libros");
		
		while (datosRS.next()) {
			String tema = new String(datosRS.getString("tema"));
			listaTemas.add(tema);
		}
		
		return (Object) listaTemas;
	}
	
	public Object getListaLibros(String temaLibro) throws SQLException {
		List <String>  listaLibros = new ArrayList<String>();
		
		this.pstatement = connection.prepareStatement(QUERY_TEMA);
		this.pstatement.setString(1, temaLibro);

		ResultSet datosRS = this.pstatement.executeQuery();
		
		while (datosRS.next()) {
			Libro libro = new Libro();
			
			libro.setId_libro(datosRS.getInt("id_libro"));
			libro.setTema(datosRS.getString("tema"));
			libro.setTitulo(datosRS.getString("titulo"));
			libro.setStock(datosRS.getInt("stock"));
			libro.setCosto(datosRS.getInt("costo"));			
			
			listaLibros.add(libro.serialize());
		}
		
		return (Object) listaLibros;
	}
	
	public Object getListaLibrosTitulo(String tituloLibro) throws SQLException {
		List <String>  listaLibros = new ArrayList<String>();
		
		this.pstatement = connection.prepareStatement(QUERY_TITULO);
		this.pstatement.setString(1, "%" + tituloLibro + "%");

		ResultSet datosRS = this.pstatement.executeQuery();
		
		while (datosRS.next()) {
			Libro libro = new Libro();
			
			libro.setId_libro(datosRS.getInt("id_libro"));
			libro.setTema(datosRS.getString("tema"));
			libro.setTitulo(datosRS.getString("titulo"));
			libro.setStock(datosRS.getInt("stock"));
			libro.setCosto(datosRS.getInt("costo"));			
			
			listaLibros.add(libro.serialize());
		}
		
		return (Object) listaLibros;
	}
	
	public Object getListaLibrosTemaTitulo(String temaTituloLibro) throws SQLException {
		List <String>  listaLibros = new ArrayList<String>();
		String[] resultSplit = temaTituloLibro.split("\\|");
		
		this.pstatement = connection.prepareStatement(QUERY_TEMATITULO);
		this.pstatement.setString(1, resultSplit[0]);
		this.pstatement.setString(2, "%" + resultSplit[1] + "%");

		ResultSet datosRS = this.pstatement.executeQuery();
		
		while (datosRS.next()) {
			Libro libro = new Libro();
			
			libro.setId_libro(datosRS.getInt("id_libro"));
			libro.setTema(datosRS.getString("tema"));
			libro.setTitulo(datosRS.getString("titulo"));
			libro.setStock(datosRS.getInt("stock"));
			libro.setCosto(datosRS.getInt("costo"));			
			
			listaLibros.add(libro.serialize());
		}
		
		return (Object) listaLibros;
	}
	
	private void desconectar() throws SQLException {
	        statement.close();
		    connection.close();
	}
}
